/*
 * digital.c
 *
 * Created: 2012-07-24 07:28:10
 *  Author: Antrykot
 */ 

#include "digital.h"
#include "trans-k.h"
#include "stdlib.h"
#include "SWLcd.h"
 
extern u16 xxx ;
extern u16 yyy ;

u16 dbg_f_max;
u16 dbg_f_min;

u16 dbg_buff[RBUFFSIZE];
u16 dbg_1_rms;
u16 dbg_0_rms;
u8 dbg_1;
u8 dbg_0;

u8 allow_internal_comm = 0;
u8 internal_tr_delay = 0;

u8 internal_spec_trans = 0;

u8 rbuff[RBUFFSIZE];
u8 bits;
u8 polarity;

u8 setbitcnt;
u8 dig_trans_finish;			

u8 t0cnt = 0;

u16 trans_f[70];


u8 modeftk = 0;
u8 kal_ask;
u16 kal_meas = 0;

u8 menu_options = 0;

u8 logon = 0;
u8 logged = 0;


u8 d_typ;
u16 d_nr;
u8 d_addr;
u16 d_data;
u8 d_crc;

u8 ds_typ;
u8 ds_addr;
u16 ds_meas;
u16 ds_data;
u8 ds_crc;

u16 leg_date;
u16 v_pow;
u16 v_aku;
u16 v_dc;
u16 v_cur;

u8 no_send = 0;

void show_f()
{
	swl_printi(dig_trans_finish);
	swl_print("e");
	for (u8 c = 0; c < dig_trans_finish; c++)
	{
		u8 ret = identify(dbg_buff[c]);
		if ( ret == 1)
		{
			dbg_1 ++;
			dbg_1_rms += dbg_buff[c];
		}
		if (ret == 0)
		{
			dbg_0 ++;
			dbg_0_rms += dbg_buff[c];
		}
		
		if (ret == 2)
		{
			//swl_print("P");
			//swl_printi(dbg_buff[c]);
			//swl_print(";");
		}
	}
	
	
	
	swl_printi(dbg_0_rms/dbg_0);
	swl_print("/");
	swl_printi(dbg_1_rms/dbg_1);
	swl_print(";");
}
#ifndef MEDIA_WX
void pulse0()
{
	
	PORTB &= ~(1 << 3);
	WAITUS(F0); 
	PORTB |= (1 << 3);
	WAITUS(F0);
	PORTB &= ~(1 << 3);
	WAITUS(F0);
	PORTB |= (1 << 3);
	WAITUS(F0);
	
}

void pulse1()
{
	
	PORTB &= ~(1 << 3);
	WAITUS(F1);
	PORTB |= (1 << 3);
	WAITUS(F1);
	PORTB &= ~(1 << 3);
	WAITUS(F1);
	PORTB |= (1 << 3);
	WAITUS(F1);
	
}
#endif

void send(u8 ftype) 
{
	
	cli();
	
	INT0_DISABLE;
 
#if !(defined(MEDIA_CO2) && defined(MEDIA_WX))
	/*
	PORTB &= ~(1 << 3);
	WAITUS(2* F0);
	PORTB |= (1 << 3);
	WAITUS(2* F0);
	PORTB &= ~(1 << 3);
	WAITUS(2* F0);
	PORTB |= (1 << 3);
	WAITUS(2* F0);
	*/
/*
	PORTB &= ~(1 << 3);
	WAITUS(2* F0);
	PORTB |= (1 << 3);
	WAITUS(2* F0);
	PORTB &= ~(1 << 3);
	WAITUS(2* F0);
	PORTB |= (1 << 3); 
	WAITUS(2* F0);
	*/
	WAITMS(3);
	
#endif

#ifdef MEDIA_WX
	PORTB &= ~(1 << 1);
	WAITUS(2* F0);
	PORTB |= (1 << 1);
	WAITUS(2* F0);
	PORTB &= ~(1 << 1);
	WAITUS(2* F0);
	PORTB |= (1 << 1);
	WAITUS(2* F0);

	PORTB &= ~(1 << 1);
	WAITUS(2* F0);
	PORTB |= (1 << 1);
	WAITUS(2* F0);
	PORTB &= ~(1 << 1);
	WAITUS(2* F0);
	PORTB |= (1 << 1);
	WAITUS(2* F0);

	WAITMS(2);
#endif

	pulse0();
	pulse0();
	pulse0();
	for (u8 c = 0; c <= setbitcnt; c++)
	{
		//LY_OFF;
		if (rbuff[c])
		{
			pulse1();
			//LY_ON;
		}
		else
		{
			pulse0(); 
			//LY_ON;
		}
	}
	

/*
	PORTB &= ~(1 << 3);
	WAITUS(2* F0);
	PORTB |= (1 << 3);
	WAITUS(2* F0);
	PORTB &= ~(1 << 3);
	WAITUS(2* F0);
	PORTB |= (1 << 3);
	WAITUS(2* F0);

*/

	EIFR |= (	1 << INTF0);		// clear INT0
	INT0_ENABLE;
	sei();

	
	
}

extern u16 xxx;

void setup_dig_trans()
{

#ifdef MEDIA_PS

static u8 meas_cnt = 0;
	meas_cnt++;
	switch(meas_cnt)
	{
		case 1:
			//rs_pr = 10045;
		
			ds_meas = rs_pr | (1 << 14);
			
			break;
		case 2:
			//rs_rh = 387;
			ds_meas = rs_rh | (2 << 14);
			break;
		case 3:
			//rs_tm = 292 + 200;
			ds_meas = rs_tm | (3 << 14);
			meas_cnt = 0;
			break;
	}
#endif
	

	crc_data_len = 0;
	add_crc8(ds_typ);
	add_crc16(nr);
	add_crc16(ds_meas);
	add_crc8(ds_alstate);
	add_crc8(ds_addr);
	add_crc16(ds_data);
	ds_crc = crc8(crc_data,crc_data_len);
	
	setbitcnt = 0;
	 
	setbits(ds_typ,6);	
	setbits(nr,11);
	setbits(ds_meas,15);
	setbits(ds_alstate,7);
	setbits(ds_addr,7);
	setbits(ds_data,15);
	setbits(ds_crc,7);

	 
	if (!no_send)
		send(0);
	PORTB &= ~(1 << 3);
}

u8 bit_cnt = 0;

void retrive_digitial()
{
	ds_addr = 0;
	ds_data = 0;
	ds_meas = rs_pom;
	ds_typ = TYPE;
	
	static u8 kal_escape = 0;

	if ((kal_ask != KAL_IDLE) && (kal_ask != KAL_ASKED) && (d_addr != 0x70))		// check if we're on the same page
	{
		kal_escape ++;
	}
	else
	{
		kal_escape = 0;
	}
	if (kal_escape > 20 )
	{
		kal_ask = KAL_IDLE;
		TS(K_ADDR_CAL_STOP,0,3);
		kal_escape = 0;
	}

	if (kal_ask == KAL_ASK)
	{
		kal_ask = KAL_ASKED;	 
	}
	if (kal_ask != KAL_IDLE && kal_ask != KAL_FINISHERR && kal_ask != KAL_FINISHOK)
	{
		ds_typ |= (1 << 6);
	}


	//ds_alstate &= ~(1 << 2);		/// TODO: Remove it

	static u8 repeat = 0;				// repeat calib commands (LZ,LS,HZ,HS)
	switch (d_addr)
	{
		case 0x00:
			// oki
		break;
		case 0x60:		// set AL output
		
			//ds_alstate |= (1 << 2);		/// TODO: Remove it
			
			
			ds_addr = 0x60;
			ds_data = d_data; 
			uw_alarms = d_data;
			
			ts_data = 0;
			if (uw_alarms & 0x01)
				ts_data = 0x01;
			if (uw_alarms & 0x02)
				ts_data |= 0x10;
				
			TS(K_ADDR_ALARMS,ts_data,2);
	
			//PORTB &= ~0xE0;
	
#ifdef MEDIA_WX

		if (uw_alarms & 0x01)
		{
			AL1_ON;
		}
		else
		{
			AL1_OFF;
		}
		
		if (uw_alarms & 0x02)
		{
			AL2_ON;
		}
		else
		{
			AL2_OFF;
		}
		
		
#endif	
	
			
		break;

		case 0x70:
		
			if (d_data > 3)
			{
				write_word(EEP_KALDATE,d_data);			// save kalibration date
			}
		
			switch (kal_ask)
			{
				case KAL_ASKED:
					repeat = 0;
					
					if (d_data == 1)
					{
						//kal_ask = KAL_DENY;
						TS(K_ADDR_DENY,0,3);
						ds_addr = 0x7E;
						ds_data = 0;
						kal_ask = KAL_IDLE;
					}
					if (d_data > 1)
					{		// accepted
						TS(K_ADDR_ACCEPT,0,3);
						ds_addr = 0x70;
						ds_data = 0;
						kal_ask = KAL_INSIDE;

					}
				
				break;
				case KAL_INSIDE:
					ds_addr = 0x70;
					ds_data = 0;
					repeat = 0;
				break;
				
				case KAL_FINISHERR:
					ds_addr = 0x7E;
					ds_data = 0;
					repeat ++;
					if (repeat > 4)
						kal_ask = KAL_IDLE;
					
					ds_typ &= ~( 1 << 6);
					break;
				case KAL_FINISHOK:
					ds_addr = 0x7F;
					ds_data = 0;
					repeat ++;
					if (repeat > 4)
						kal_ask = KAL_IDLE;
					ds_typ &= ~( 1 << 6);
					break;
				case KAL_ZERO_L:
					ds_addr = 0x71;
					ds_data = kal_meas;
					repeat ++;
					if (repeat > 4)
						kal_ask = KAL_INSIDE;
					break;
				case KAL_ZERO_H:
					ds_addr = 0x73;
					ds_data = kal_meas ;
					repeat ++;
					if (repeat > 4)
						kal_ask = KAL_INSIDE;
					break;
				case KAL_SENS_L:
					ds_addr = 0x72 ;
					ds_data = kal_meas;
					repeat ++;
					if (repeat > 4)
						kal_ask = KAL_INSIDE;
					break;
				case KAL_SENS_H:
					ds_addr = 0x74;
					ds_data = kal_meas;
					repeat ++;
					if (repeat > 4)
						kal_ask = KAL_INSIDE;
					break;
				case KAL_SERWIS:
					ds_addr = 0x7B;
					ds_data = kal_meas;
					repeat ++;
					if (repeat > 4)
						kal_ask = KAL_INSIDE;
					break;
				case KAL_IDLE:
					ds_addr = 0x7E;
					ds_data = 0;
					break;					
			}					

		break;
		case 0x80:		// leg
			ds_addr = 0x80;
			ds_data = leg_date;
		break;
		case 0x81:		// leg
			ds_addr = 0x81;
			ds_data = VERSION;
		break;
		case 0x8A:
			ds_addr = 0x8A;
			ds_data = v_aku;
		break;
		case 0x88:
			ds_addr = 0x88;
			ds_data = v_pow;
			break;
		case 0x8D:
			ds_addr = 0x8D;
			ds_data = v_dc;
			break;
		case 0x89:
			ds_addr = 0x89;
			ds_data = v_cur;
			break;
		case 0x8f:
			ds_addr = 0x8F;
			ds_data = v_temp;
		case 0x90:
			ds_addr = 0x90;
			ds_data = (1 << 14);
		break;
		case 0x91:
			ds_addr = 0x91;
			ds_data = (1 << 14) | 196;
		break;
		case 0x92:
			ds_addr = 0x92;
			ds_data = (1 << 15);
		break;
		case 0x93:
			ds_addr = 0x93;
			ds_data = (1 << 15) | 297;
		break;
		case 0x98:
			ds_addr = 0x98;
			ds_data = read_word(EEP_KALDATE);
			break;

	}


	d_nr = nr;
	 
	 
	// if we are in kalib, and it is not KAL_FINISH-xx then add kalibration bit to type information.
	if ((kal_ask != KAL_IDLE) && (kal_ask != KAL_FINISHOK) && (kal_ask != KAL_FINISHERR))
	{
		ds_typ |= (1 << 6);
	}
	
	#ifdef MEDIA_WX
		if (OUT2)
		ds_alstate |= (1 << 1);
		if (OUT1)
		ds_alstate |= (1 << 0);

	#endif
	
 
	setup_dig_trans();	
	logged = 1;


}

void setbits(u16 value, u8 cnt)
{
	for (i8 c = cnt; c >= 0; c--)
	{
		rbuff[setbitcnt] = ( value & (1 << c) ) >> c;
		setbitcnt++;
	}
}

u16 getbits(u8 cnt)
{
	u16 value = 0;
	i8 c = cnt;
	for (; c >= 0; c--)
	{
		value |= (rbuff[bit_cnt] << c);
		bit_cnt++;
	}
	return value;
}


u8 get_digi_trans()
{
	bit_cnt = 2;
	d_typ = getbits(5);	// 6 bits
	d_nr = getbits(11);
	d_addr = getbits(7);
	d_data = getbits(15);
	d_crc = getbits(7);
	
	crc_data_len = 0;
	add_crc8(d_typ);
	add_crc16(d_nr);
	add_crc8(d_addr);
	add_crc16(d_data);
	u8 crc_c = crc8(crc_data,crc_data_len);


	if (d_crc != crc_c)
	{
		swl_clear();
		swl_printi(d_crc);
		swl_print("crc");
		swl_printi(crc_c);
		swl_print(";");
		swl_printi(d_typ);
		swl_setpos(16);
		swl_printi(d_nr);
		swl_print(";");
		swl_printi(d_addr);
		swl_print(";");
		swl_printi(d_data);
		swl_print(";");
		swl_proceed(); 
		
		return 0;
	}

	
	

	if (d_typ != TYPE || d_nr != nr)		// It's not me - do nothing.
	{
		
		swl_clear();
		swl_printi(d_typ);
		swl_print("type!");
		swl_printi(TYPE);
		swl_print(";");
		swl_setpos(16);
		swl_printi(d_nr);
		swl_print("nr!");
		swl_printi(nr);
		swl_print(";");

		swl_proceed();
		
		return 0;
	}	
	
	ds_meas = rs_pom;
	retrive_digitial();
/*
	
	swl_clear();
	swl_print("L:");
	swl_printi(d_typ);
	swl_print(";");
	swl_printi(d_nr);
	swl_setpos(16);
	swl_printi(d_addr);
	swl_print(";");
	swl_printi(d_data);
	swl_print(";");
	swl_printi(d_crc);
	swl_print(";");
	swl_proceed();
*/
	
	//allow_internal_comm = 1;
	return 1;
}


void get_short_trans()
{
	//LY_ON;

	
	static u8 seed_init = 0;
	seed_init ++;
	if (!seed_init)
	{
		seed_init = 1;
		srand(v_aku * v_pow);
	}
	
	if (logged)		// I'm already logged on
		return;
	
	bit_cnt = 2;	// skip 2 first bits
	u8 v1 = getbits(7);	// 8 bits
	u8 v2 = getbits(7);	// 8 bits
	u8 crc_c = getbits(7);
	bit_cnt = 0;
	
	crc_data_len = 0;
	add_crc8(v1);
	add_crc8(v2);

	u8 crc_v = crc8(crc_data,crc_data_len);
	
	
	if (crc_c != crc_v)
	{
		swl_setpos(16);
		swl_print("SH-CRC!");
		//show_f();
		swl_proceed();

		return;
	}
	
	swl_setpos(16);
	swl_print("SHORT");
	//show_f();
	swl_proceed();
		
	u16 rnd = ( rand() % 20 )  +4;
	//rnd = 4;
	
	logon = 1;		// ISR(INT0) will clear logon if line will be used by another device 
	
	crc_data_len = 0;
	add_crc8(TYPE);
	add_crc16(nr);
	ds_crc = crc8(crc_data,crc_data_len);
	
	setbitcnt = 0;
	setbits(TYPE,5);
	setbits(nr,11);
	setbits(ds_crc,7);
	
	
	for (u8 c = 0; c < rnd; c++)
	{
		WAITUS(250);
	}
	
	
	if (!logon)			// if line already used
		return;
	
	send(1);			// send short(1) frame
	PORTB &= ~(1 << 3); // clear my sending pin

	//INT0_DISABLE;
	//allow_internal_comm = 1;
	bits = 0;
	
}

 

inline u8 identify(u16 t1value)
{
	/*
#ifdef DEBUG_F
	if (t1value > dbg_f_max)
		dbg_f_max = t1value;
	
	if (t1value < dbg_f_min)
		dbg_f_min = t1value;
#endif
	if ( ( t1value > DF1 ) && (t1value < GF1))
	{
		return 1;
	}
		*/
	
	if ( ( t1value > DF0 ) && (t1value < GF0))
	{
		return 0;
	}
	

	return 1;
}

inline void add_mem(u8 val)
{
	
	//if (val > 1)
	//{
	//	bits = 0;
	//	return;
	//}
 
	rbuff[bits] = val;
	bits++;
}

